package com.example.mattrigle;

import java.io.IOException;

import com.example.mattrigle.SeekBar.SeekBarListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class GameCanvas extends View implements SeekBarListener,SpinClickListener {

	// ==========================================================
	// Delegate & Callback
	// ==========================================================
	public abstract interface InteractListener {
		public void onBeginDrag(SeekBar obj, float value,long currentTime,Point position);

		public void onValueChange(SeekBar obj, float value,long currentTime,Point position);

		public void onEndDrag(SeekBar obj, float value,long currentTime,long elapsedTime,Point position);
	}

	public abstract interface InteractClickListener {
		public void onClick(SpinButton obj, float value,long currentTime,Point location);
	}

	// ==========================================================
	// Constants
	// ==========================================================
	private int TRACK_HEIGHT = 50;

	private class GameCanvasOption
	{
		public  boolean isViewForAnimate = false;
		public int align = ALIGN_CENTER;
		public int valign = VALIGN_MIDDLE;
		public int pos_hand = POS_HAND_SLIDE;
		public Point position = new Point(0, 0);
		public boolean isShowAngle = true;
		public boolean isShowSeekBar = true;
		public boolean isLock = false;
		public float thumb_length = 1f;
		public float scale = 0.4f;
		public int num_float_bit = 1;
		public boolean isEnableCacheValue = true;
		public int mode = MODE_DISPLAY;
		public boolean isHideCorner = true;
		public boolean multiCorner = false;
		public boolean isHideHand = true;
		public boolean isMultiActive = false;
		public boolean isCosActive = true;
		public boolean isHideArc = false;
		public boolean isHideLabel = false;
		
		public GameCanvasOption clone()
		{
			GameCanvasOption tmp = new GameCanvasOption();
			tmp.isViewForAnimate = isViewForAnimate;
			tmp.align = align;
			tmp.isViewForAnimate = isViewForAnimate;
			tmp.align = align;
			tmp.valign = valign;
			tmp.position = position;
			tmp.multiCorner = multiCorner;
			tmp.isShowAngle = isShowAngle;
			tmp.isShowSeekBar = isShowSeekBar;
			tmp.isLock = isLock;
			tmp.thumb_length = thumb_length;
			tmp.isHideArc = isHideArc;
			tmp.scale = scale;
			tmp.num_float_bit = num_float_bit;
			tmp.isEnableCacheValue = isEnableCacheValue;
			tmp.mode = mode;
			tmp.isHideCorner = isHideCorner;
			tmp.isHideHand = isHideHand;
			tmp.isMultiActive = isMultiActive;
			tmp.isCosActive = isCosActive;
			tmp.isHideLabel = isHideLabel;
			return tmp;
		}
	}
	
	// ==========================================================
	// Field
	// ==========================================================
	private Paint tanPaint = new Paint();
	private Paint anglePaint = new Paint();
	private Paint markAnglePaint = new Paint();
	private GifAnimationDrawable corner_cos_anim;
	private GifAnimationDrawable corner_sin_anim;

    private RectF cosRectF = null;
    private RectF sinRectF = null;
	private Point offset = new Point(0, 0);

	private int doc_width = 120, doc_height = 260;
	private int object_width = 120, object_height = 260;
	private float cosDegree = 0f;

	private SeekBar cosSeekBar, sinSeekBar, tanSeekBar;
	private SeekBar mCosSeekBar, mSinSeekBar;
	
	private GameCanvasOption option = new GameCanvasOption();
	
	// ==========================================================
	// Properties
	// ==========================================================
	public static final int ALIGN_CENTER = 0;
	public static final int ALIGN_LEFT = 1;
	public static final int ALIGN_RIGHT = 2;

	public int getAlign() {
		return this.option.align;
	}

	public void setAlign(int align) {
		switch (align) {
		case ALIGN_CENTER:
		case ALIGN_LEFT:
		case ALIGN_RIGHT:
			this.option.align = align;
			break;
		default:
			this.option.align = ALIGN_CENTER;
			break;
		}
		calPos();
	}

	public static final int VALIGN_MIDDLE = 0;
	public static final int VALIGN_TOP = 1;
	public static final int VALIGN_BOTTOM = 2;

	public int getValign() {
		return this.option.valign;
	}

	public void setValign(int valign) {
		switch (valign) {
		case ALIGN_CENTER:
		case ALIGN_LEFT:
		case ALIGN_RIGHT:
			this.option.valign = valign;
			break;
		default:
			this.option.valign = VALIGN_MIDDLE;
			break;
		}
		calPos();
	}

	public void setPosition(int x, int y) {
		this.option.position.x = x;
		this.option.position.y = y;
		calPos();
	}

	public Point getPosition() {
		return this.option.position;
	}

	public boolean IsShowAngle() {
		return this.option.isShowAngle;
	}

	public void setShowAngle(boolean isShowAngle) {
		this.option.isShowAngle = isShowAngle;
		this.invalidate();
	}

	public boolean IsShowSeekBar() {
		return this.option.isShowSeekBar;
	}

	public void setShowSeekBar(boolean isShowSeekBar) {
		this.option.isShowSeekBar = isShowSeekBar;
		this.invalidate();
	}

	public boolean getLockSeekBar() {
		return this.option.isLock;
	}

	public void LockSeekBar(boolean isLock) {
		this.option.isLock = isLock;
	}

	public float getMaxTanThumbnailLength() {
		return this.option.thumb_length;
	}

	public void setMaxTanThumbnailLength(float length) {
		this.option.thumb_length = length > 1f ? 1f : length<0.5f?0.5f:length;
		mCosSeekBar.setMaximumLength(this.option.thumb_length);
		mSinSeekBar.setMaximumLength(this.option.thumb_length);
	}

	public float getScale() {
		return this.option.scale;
	}

	public void setScale(float scale) {
		this.option.scale = scale < 0.1f ?  0.1f : scale>0.6f?0.6f:scale;
		this.sinSeekBar.setScale(scale);
		this.cosSeekBar.setScale(scale);
		this.tanSeekBar.setScale(scale);
		calSize();
	}

	public int getNumOfFloatBit() {
		return this.option.num_float_bit;
	}

	public void setNumOfFloatBit(int num_float_bit) {
		this.option.num_float_bit = num_float_bit < 1 ? 1 : num_float_bit > 6 ? 6
				: num_float_bit;
		this.invalidate();
	}

	public boolean isEnableCacheValue() {
		return this.option.isEnableCacheValue;
	}

	public void setEnableCacheValue(boolean isEnableCacheValue) {
		this.option.isEnableCacheValue = isEnableCacheValue;
	}

	public boolean getMultiCorner()
	{
		return this.option.multiCorner;
	}

	public void setMultiCorner(boolean multiCorner) {
		this.option.multiCorner = multiCorner;
		this.invalidate();
	}

	public boolean IsHideCorner()
	{
		return this.option.isHideCorner;
	}

	public void setHideCorner(boolean isHideCorner) {
		this.option.isHideCorner = isHideCorner;

		if (corner_sin_anim == null) {
			try {
				corner_sin_anim = new GifAnimationDrawable(this, getResources()
						.openRawResource(R.raw.cartoon1), true);

			} catch (NotFoundException e) {
				corner_sin_anim = null;
			} catch (IOException e) {
				corner_sin_anim = null;
			}
			if(corner_sin_anim!=null)
				{
					corner_sin_anim.setSmoothScale(0.0025f*object_width);
					corner_sin_anim.setForeground(new Rect(mSinSeekBar.getCursorX() - 40,
					mSinSeekBar.getCursorY() - 60,
					mSinSeekBar.getCursorX() + 60,
					mSinSeekBar.getCursorY() + 40));
				}
			
		}
		if (corner_cos_anim == null) {
			try {
				corner_cos_anim = new GifAnimationDrawable(this, getResources()
						.openRawResource(R.raw.cartoon1), true);

			} catch (NotFoundException e) {
				corner_cos_anim = null;
			} catch (IOException e) {
				corner_cos_anim = null;
			}

			if(corner_cos_anim!=null)
				{
					corner_cos_anim.setSmoothScale(0.0025f*object_width);
					corner_cos_anim.setForeground(new Rect(mCosSeekBar.getCursorX() - 40,
					mCosSeekBar.getCursorY() - 60,
					mCosSeekBar.getCursorX() + 60,
					mCosSeekBar.getCursorY() + 40));
				
				}

		}
		if(!this.option.isHideCorner)
		{
			corner_cos_anim.start();
			corner_sin_anim.start();
		}
		else
		{
			corner_cos_anim.stop();
			corner_sin_anim.stop();
			this.invalidate();
		}
	}

	public static final int POS_HAND_SEEKBAR = 0;
	public static final int POS_HAND_SLIDE = 1;
	public static final int POS_HAND_BOTH = 2;

	public int getPosHand()
	{
		return this.option.pos_hand;
	}
	
	public void setPosHand(int pos_hand) {
		this.option.pos_hand = (pos_hand==POS_HAND_SEEKBAR||pos_hand==POS_HAND_SLIDE||pos_hand==POS_HAND_BOTH)?pos_hand:POS_HAND_SLIDE;
		this.invalidate();
	}

	public boolean IsHideLabel()
	{
		return this.option.isHideLabel;
	}
	
	public void setHideLabel(boolean isHideLabel) {
		this.option.isHideLabel = isHideLabel;
		
		this.sinSeekBar.setHideLabel(isHideLabel);
		this.mSinSeekBar.setHideLabel(isHideLabel);
		this.cosSeekBar.setHideLabel(isHideLabel);
		this.mCosSeekBar.setHideLabel(isHideLabel);
		this.invalidate();
	}

	public boolean IsHideHand()
	{
		return this.option.isHideHand;
	}
	
	public void setHideHand(boolean isHideHand) {
		this.option.isHideHand = isHideHand;
		
		this.sinSeekBar.setHideHand(isHideHand||this.option.isViewForAnimate||(this.option.isCosActive&&!this.option.isMultiActive));
		this.mSinSeekBar.setHideHand(isHideHand||(this.option.isCosActive&&!this.option.isMultiActive));
		this.cosSeekBar.setHideHand(isHideHand||this.option.isViewForAnimate||(!this.option.isCosActive&&!this.option.isMultiActive));
		this.mCosSeekBar.setHideHand(isHideHand||(!this.option.isCosActive&&!this.option.isMultiActive));
		this.invalidate();
	}

	public void setCosActive(boolean isCosActive) {
		this.option.isCosActive = isCosActive;
		
		this.sinSeekBar.setEnable(!isCosActive);
		this.sinSeekBar.setHideLabel(isCosActive);
		this.mSinSeekBar.setEnable(!isCosActive);
		
		this.cosSeekBar.setEnable(isCosActive);
		this.cosSeekBar.setHideLabel(!isCosActive);
		this.mCosSeekBar.setEnable(isCosActive);

		
		
		setHideHand(this.option.isHideHand);
	}

	private float line_width = 1f;

	public float getLineWidth() {
		return line_width * 2;
	}

	public void setLineWidth(int line_width) {
		this.line_width = (line_width < 1) ? 1 : line_width;
		this.tanPaint.setStrokeWidth(line_width);
		
		this.cosSeekBar.setLineWidth(line_width/3);
		this.sinSeekBar.setLineWidth(line_width/3);
		this.tanSeekBar.setLineWidth(line_width/3);
		this.mCosSeekBar.setLineWidth(line_width);
		this.mSinSeekBar.setLineWidth(line_width);
	}

	public boolean IsMultiActive()
	{
		return this.option.isMultiActive;
	}
	public void setMultiActive(boolean isMultiActive) {
		this.option.isMultiActive = isMultiActive;
		this.sinSeekBar.setEnable(isMultiActive);
		this.mSinSeekBar.setEnable(isMultiActive);
		this.cosSeekBar.setEnable(isMultiActive);
		this.sinSeekBar.setHideLabel(!isMultiActive);
		this.cosSeekBar.setHideLabel(!isMultiActive);
		this.mCosSeekBar.setEnable(isMultiActive);
		if(!isMultiActive)
		{
			this.setCosActive(this.option.isCosActive);

			if(!this.option.isCosActive)
				this.sinSeekBar.setHideLabel(true);
			else
				this.cosSeekBar.setHideLabel(true);
		}
		setHideHand(this.option.isHideHand);
		setHideCorner(this.option.isHideCorner);
		this.invalidate();
	}
	
	
	//=====================================================================
	
	private float weight_point = 0.0025f;
	public void setWeightPoint(float weight_point)
	{
		this.weight_point = weight_point;
	}
	private Drawable iconSpin,labelDrawable,inactiveLabelDrawable;
	private Drawable plusDrawable,plusInactiveDrawable,plusHoverDrawable;
	private Drawable minusDrawable,minusInactiveDrawable,minusHoverDrawable;
	private Paint spinPaint = new Paint();
	private Paint spinInactivePaint = new Paint();
	private Paint titlePaint = new Paint();
	private Paint titleInactivePaint = new Paint();
	private Point vtSinSpinTxt = new Point(),vtCosSpinTxt = new Point();
	

	private SpinButton cosLabelBodaries,sinLabelBodaries;
	private SpinButton cosPlusBodaries,sinPlusBodaries;
	private SpinButton cosMinusBodaries,sinMinusBodaries;
	
	
	//=====================================================================
	
	
	
	// ==========================================================
	// Constructor
	// ==========================================================
	// For xml layout
	public GameCanvas(Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.GameCanvas);
		this.option.isViewForAnimate = a.getBoolean(
				R.styleable.GameCanvas_is_animation_view, false);
		
		a.recycle();

		loadContent(context);
		Initialize();
	}

	// For activity ->setContentView
	public GameCanvas(Context context, boolean isViewForAnimate) {
		super(context);

		this.option.isViewForAnimate = isViewForAnimate;
		loadContent(context);
		Initialize();
	}

	
	// ==========================================================
	// Process & Operand Method
	// ==========================================================
	private void calPos() {
		float aw = (((float)object_width)/320f);
		
		switch (this.option.align) {
		case ALIGN_CENTER:
			offset.x = this.option.position.x + ((doc_width - object_width) / 2);
			break;
		case ALIGN_LEFT:
			offset.x = this.option.position.x  +(int)(10*aw)+ this.sinSeekBar.getThumbWidth() / 2;
			break;
		case ALIGN_RIGHT:
			offset.x = this.option.position.x
					+ (doc_width - object_width - this.sinSeekBar
							.getThumbWidth() / 2);
			break;
		}
		switch (this.option.valign) {
		case VALIGN_MIDDLE:
			offset.y = this.option.position.y + this.sinSeekBar.getThumbHeight() / 2+ ((doc_height - object_height) / 2);
			break;
		case VALIGN_TOP:
			offset.y = this.option.position.y + this.sinSeekBar.getThumbHeight() / 2;
			break;
		case VALIGN_BOTTOM:
			offset.y = this.option.position.y
					+ (doc_height - object_height - this.sinSeekBar
							.getThumbHeight() / 2);
			break;
		}
		
		int TRACKER_HEIGHT = (int)(50f*aw);
		tanSeekBar.setPosition(offset.x, offset.y + object_width
				+ (int) ((float) (1f / 2f) * TRACKER_HEIGHT));
		
		int shap_size = (int)(TRACKER_HEIGHT*0.8);
		int cy = offset.y + object_width
				+ (int) ((float) (3f / 2f) * TRACKER_HEIGHT);
		int space = (int)(aw*30);
		cosSeekBar.setPosition(offset.x, cy);

		cy +=5;

		vtCosSpinTxt.x = offset.x + cosSeekBar.getWidth()+ (int)(space*0.5);
		vtCosSpinTxt.y = cy+(int)(24*aw);
		cosMinusBodaries.bondary = new Rect(
    			offset.x + cosSeekBar.getWidth()+ (int)(space*1.8),
    			cy,
    			offset.x  + cosSeekBar.getWidth()+ shap_size+ (int)(space*1.8),
    			cy+ shap_size);
		cosLabelBodaries.bondary = new Rect(
        		cosMinusBodaries.bondary.right ,
        		cy,
        		cosMinusBodaries.bondary.right + (int)(space*0.8)+ shap_size,
        		cy + shap_size);
		
    	cosPlusBodaries.bondary = new Rect(
    			cosLabelBodaries.bondary.right,
    			cy,
    			cosLabelBodaries.bondary.right+ shap_size,
    			cy+ shap_size);

		int sy = offset.y + object_width
				+ (int) ((float) (5f / 2f) * TRACKER_HEIGHT);
		sinSeekBar.setPosition(offset.x, sy);
		
		sy +=5;

		vtSinSpinTxt.x = offset.x + sinSeekBar.getWidth()+ (int)(space*0.5);
		vtSinSpinTxt.y = sy+(int)(24*aw);
    	sinMinusBodaries.bondary = new Rect(
    			offset.x + sinSeekBar.getWidth()+ (int)(space*1.8),
    			sy,
    			offset.x  + sinSeekBar.getWidth()+ shap_size+ (int)(space*1.8),
    			sy+ shap_size);
        sinLabelBodaries.bondary = new Rect(
        		sinMinusBodaries.bondary.right,
        		sy,
        		sinMinusBodaries.bondary.right + (int)(space*0.8)+ shap_size,
        		sy + shap_size);
    	sinPlusBodaries.bondary = new Rect(
    			sinLabelBodaries.bondary.right,
    			sy,
    			sinLabelBodaries.bondary.right+ shap_size,
    			sy+ shap_size);
    	
		mSinSeekBar.setPosition(offset.x, offset.y);
		mCosSeekBar.setPosition(offset.x, offset.y + object_width
				- (int) ((float) (1f / 2f) * TRACK_HEIGHT));

		int mWidth = (int)(mCosSeekBar.getProgress()*mCosSeekBar.getWidth());
		mWidth = mWidth>30?30:mWidth;
		int mHeight = (int)((mSinSeekBar.getProgress())*mSinSeekBar.getHeight());
		mHeight = mHeight>30?30:mHeight;
		
		cosRectF = new RectF(mCosSeekBar.getCursorX()-mWidth,  mCosSeekBar.getCursorY()-mWidth, mCosSeekBar.getCursorX()+mWidth, mCosSeekBar.getCursorY()+mWidth);
        sinRectF = new RectF(mSinSeekBar.getCursorX()-mHeight,  mSinSeekBar.getCursorY()-mHeight, mSinSeekBar.getCursorX()+mHeight, mSinSeekBar.getCursorY()+mHeight);
       
        if(corner_sin_anim!=null)corner_sin_anim.setForeground(new Rect(mSinSeekBar.getCursorX()-40,  mSinSeekBar.getCursorY()-60, mSinSeekBar.getCursorX()+60, mSinSeekBar.getCursorY()+40));
        if(corner_cos_anim!=null)corner_cos_anim.setForeground(new Rect(mCosSeekBar.getCursorX()-40,  mCosSeekBar.getCursorY()-60, mCosSeekBar.getCursorX()+60, mCosSeekBar.getCursorY()+40));
        
        
	}

	private void calSize() {
		object_width = (int) (doc_height * this.option.scale);
		if(object_width>doc_width*0.75f)
			object_width = (int)(doc_width*0.75f);
		if (!this.option.isViewForAnimate)
			object_height = (doc_height > object_width + (TRACK_HEIGHT * 4)) ? object_width
					+ (TRACK_HEIGHT * 4)
					: doc_height;
		else
			object_height = object_width;

		cosSeekBar.setHeight(TRACK_HEIGHT);
		cosSeekBar.setWidth(object_width);

		sinSeekBar.setHeight(TRACK_HEIGHT);
		sinSeekBar.setWidth(object_width);

		tanSeekBar.setHeight(TRACK_HEIGHT);
		tanSeekBar.setWidth(object_width);
		
		mCosSeekBar.setHeight(TRACK_HEIGHT);
		mCosSeekBar.setWidth(object_width);

		mSinSeekBar.setHeight(object_width);
		mSinSeekBar.setWidth(TRACK_HEIGHT);

		float aw = 0.0025f*object_width;
		this.tanPaint.setStrokeWidth(aw*line_width);
		this.cosSeekBar.setLineWidth((int)(aw*line_width/2));
		this.sinSeekBar.setLineWidth((int)(aw*line_width/2));
		this.tanSeekBar.setLineWidth((int)(aw*line_width/2));
		this.mCosSeekBar.setLineWidth((int)(aw*line_width));
		this.mSinSeekBar.setLineWidth((int)(aw*line_width));

		this.cosSeekBar.setSmoothScale(aw);
		this.sinSeekBar.setSmoothScale(aw);
		this.tanSeekBar.setSmoothScale(aw);

		tanPaint.setTextSize(25*aw);
		anglePaint.setTextSize(55*aw);
		tanPaint.setStrokeWidth((int)(aw*line_width));
		spinPaint.setTextSize(50*aw);
		spinInactivePaint.setTextSize(50*aw);
		titlePaint.setTextSize(50*aw);
		titleInactivePaint.setTextSize(50*aw);
		
		calPos();
		newStageWithAngle(true, 90);
	}

	private void calProgress(SeekBar obj, float progress,boolean saveData)
	{
		if (progress < 0 )
			progress = 0;
		if (progress > 1)
			progress = 1;
		if (obj == cosSeekBar) {
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "cosSeekValue", progress
						+ "f");
			mCosSeekBar.setProgress(cosSeekBar.getProgress()*this.option.thumb_length);
			double Vl_w = Math.sin(Math.acos(progress)) * obj.getWidth();
			cosDegree = (float) ((180 / Math.PI) * (Math.acos(progress)));
			sinSeekBar.setProgress((float) (Vl_w / obj.getWidth()));
			mSinSeekBar.setProgress(sinSeekBar.getProgress()*this.option.thumb_length);
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "sinSeekValue",
						sinSeekBar.getProgress() + "f");
		}
		if (obj == sinSeekBar) {
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "sinSeekValue", progress
					+ "f");
			mSinSeekBar.setProgress(sinSeekBar.getProgress()*this.option.thumb_length);
			double Hl_h = Math.cos(Math.asin(progress)) * obj.getWidth();
			cosDegree = (float) ((180 / Math.PI) * (Math.asin(progress)));
			cosSeekBar.setProgress((float) (Hl_h / obj.getWidth()));
			mCosSeekBar.setProgress(cosSeekBar.getProgress()*this.option.thumb_length);
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "cosSeekValue",
					cosSeekBar.getProgress() + "f");
		}
		if (obj == mCosSeekBar) {
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "cosSeekValue", progress/this.option.thumb_length
					+ "f");
			cosSeekBar.setProgress(mCosSeekBar.getProgress()/this.option.thumb_length);
			
			double Vl_w = Math.sin(Math.acos(cosSeekBar.getProgress())) * obj.getWidth();
			cosDegree = (float) ((180 / Math.PI) * (Math.acos(cosSeekBar.getProgress())));
			sinSeekBar.setProgress((float) (Vl_w / obj.getWidth()));
			
			mSinSeekBar.setProgress(sinSeekBar.getProgress()*this.option.thumb_length);
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "sinSeekValue",
					sinSeekBar.getProgress() + "f");
		}

		int mWidth = (int)(mCosSeekBar.getProgress()*mCosSeekBar.getWidth());
		mWidth = mWidth>30?30:mWidth;
		int mHeight = (int)(((obj == mSinSeekBar)?mSinSeekBar.getProgress(true):mSinSeekBar.getProgress())*mSinSeekBar.getHeight());
		mHeight = mHeight>30?30:mHeight;
		sinRectF = new RectF(mSinSeekBar.getCursorX()-mHeight,  mSinSeekBar.getCursorY()-mHeight, mSinSeekBar.getCursorX()+mHeight, mSinSeekBar.getCursorY()+mHeight);
        
		if (obj == mSinSeekBar) {
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "sinSeekValue",
					mSinSeekBar.getProgress(true)/this.option.thumb_length + "f");
			sinSeekBar.setProgress(mSinSeekBar.getProgress(true)/this.option.thumb_length);
			mSinSeekBar.setProgress(sinSeekBar.getProgress()*this.option.thumb_length);
			
			double Hl_h = Math.cos(Math.asin(sinSeekBar.getProgress()))
					* obj.getWidth();
			cosDegree = (float) ((180 / Math.PI) * (Math.asin(sinSeekBar.getProgress())));
			cosSeekBar.setProgress((float) (Hl_h / obj.getWidth()));
			
			mCosSeekBar.setProgress(cosSeekBar.getProgress()*this.option.thumb_length);
			if(saveData && this.option.isEnableCacheValue)
				UDataStorage.setStrData(this.getContext(), "cosSeekValue",
					cosSeekBar.getProgress(true) + "f");

			mHeight = (int)(((obj == mSinSeekBar)?mSinSeekBar.getProgress():mSinSeekBar.getProgress())*mSinSeekBar.getHeight());
			mHeight = mHeight>30?30:mHeight;
			sinRectF = new RectF(mSinSeekBar.getCursorX()-mHeight,  mSinSeekBar.getCursorY()-mHeight, mSinSeekBar.getCursorX()+mHeight, mSinSeekBar.getCursorY()+mHeight);
	        
		}

		tanSeekBar.setProgress(1f);

		cosRectF = new RectF(mCosSeekBar.getCursorX()-mWidth,  mCosSeekBar.getCursorY()-mWidth, mCosSeekBar.getCursorX()+mWidth, mCosSeekBar.getCursorY()+mWidth);
        
        if(corner_sin_anim!=null)corner_sin_anim.setForeground(new Rect(mSinSeekBar.getCursorX()-40,  mSinSeekBar.getCursorY()-60, mSinSeekBar.getCursorX()+60, mSinSeekBar.getCursorY()+40));
        if(corner_cos_anim!=null)corner_cos_anim.setForeground(new Rect(mCosSeekBar.getCursorX()-40,  mCosSeekBar.getCursorY()-60, mCosSeekBar.getCursorX()+60, mCosSeekBar.getCursorY()+40));
        
	}
	
 	private void loadContent(Context context) {

		cosSeekBar = new SeekBar(context, this, SeekBar.HORIZONTAL, false);
		if (!this.option.isViewForAnimate)
			cosSeekBar.setOnValueChanged(this);
		sinSeekBar = new SeekBar(context, this, SeekBar.HORIZONTAL, false);
		if (!this.option.isViewForAnimate)
			sinSeekBar.setOnValueChanged(this);
		tanSeekBar = new SeekBar(context, this, SeekBar.HORIZONTAL, false);
		if (!this.option.isViewForAnimate)
			tanSeekBar.setOnValueChanged(this);

		mCosSeekBar = new SeekBar(context, this, SeekBar.HORIZONTAL, true);
		//if (!this.option.isViewForAnimate)
			mCosSeekBar.setOnValueChanged(this);
		mSinSeekBar = new SeekBar(context, this, SeekBar.VERTICAL, true);
		//if (!this.option.isViewForAnimate)
			mSinSeekBar.setOnValueChanged(this);

		tanPaint.setColor(0xff86c5f8);
		tanPaint.setStyle(Style.STROKE);
		tanPaint.setAntiAlias(true);

        Typeface face = Typeface.createFromAsset(getContext().getAssets(), "fonts/THA0085.ttf");
        anglePaint.setTypeface(face);
		anglePaint.setARGB(255, 58, 58, 58);
		anglePaint.setStyle(Style.FILL_AND_STROKE);
		anglePaint.setAntiAlias(true);
		anglePaint.setStrokeWidth(1);

		spinPaint.setTypeface(face);
		spinPaint.setAntiAlias(true);
		spinPaint.setARGB(255, 58, 58, 58);
		
		spinInactivePaint.setTypeface(face);
		spinInactivePaint.setAntiAlias(true);
		spinInactivePaint.setARGB(255, 220, 220, 220);

		titlePaint.setTypeface(face);
		titlePaint.setAntiAlias(true);
		titlePaint.setARGB(255, 58, 58, 58);
		
		titleInactivePaint.setTypeface(face);
		titleInactivePaint.setAntiAlias(true);
		titleInactivePaint.setARGB(255, 120, 120, 120);

		markAnglePaint.setColor(Color.GREEN);
		markAnglePaint.setStyle(Style.FILL_AND_STROKE);
		markAnglePaint.setAntiAlias(true);
		markAnglePaint.setStrokeJoin(Paint.Join.ROUND);
		markAnglePaint.setStrokeWidth(this.line_width);

		cosSeekBar.setTheme(SeekBar.THEME_GREEN_INVERT);
		sinSeekBar.setTheme(SeekBar.THEME_RED_INVERT);
		tanSeekBar.setTheme(SeekBar.THEME_BLUE);
		mCosSeekBar.setTheme(SeekBar.THEME_GREEN);
		mSinSeekBar.setTheme(SeekBar.THEME_RED);

		plusDrawable = context.getResources().getDrawable(R.drawable.btn_plus);
		minusDrawable = context.getResources().getDrawable(R.drawable.btn_minus);
		
		plusInactiveDrawable = context.getResources().getDrawable(R.drawable.btn_plus_inactive);
		minusInactiveDrawable = context.getResources().getDrawable(R.drawable.btn_minus_inactive);
		
		plusHoverDrawable = context.getResources().getDrawable(R.drawable.btn_plus_hover);
		minusHoverDrawable = context.getResources().getDrawable(R.drawable.btn_minus_hover);
		
		iconSpin = context.getResources().getDrawable(R.drawable.zeta);
		labelDrawable = context.getResources().getDrawable(R.drawable.label_region);
		inactiveLabelDrawable = context.getResources().getDrawable(R.drawable.inactive_label_region);
		
		cosLabelBodaries = new SpinButton();
		cosLabelBodaries.listener = this;
		sinLabelBodaries = new SpinButton();
		sinLabelBodaries.listener = this;
		
		cosPlusBodaries = new SpinButton();
		cosPlusBodaries.listener = this;
		sinPlusBodaries = new SpinButton();
		sinPlusBodaries.listener = this;
		
		cosMinusBodaries = new SpinButton();
		cosMinusBodaries.listener = this;
		sinMinusBodaries = new SpinButton();
		sinMinusBodaries.listener = this;
		
	}

	// ==========================================================
	// Public Method
	// ==========================================================
	private static final int MODE_DISPLAY = 5;
	public static final int MODE_CAPTURE_FULL = 6;
	public static final int MODE_CAPTURE_SAMPLE = 7;

	public Bitmap saveSignature(int mode) {
		return saveSignature(mode, Color.TRANSPARENT);
	}
	
	@SuppressWarnings("finally")
	public Bitmap saveSignature(int mode ,int  backgroundColor) {
		GameCanvasOption restoreOption = this.option.clone();
		
		this.option.mode = (mode == MODE_CAPTURE_FULL || mode == MODE_CAPTURE_SAMPLE) ? mode
				: MODE_CAPTURE_FULL;
		this.option.isHideArc = true;
		this.setAlign(ALIGN_CENTER);
		this.setShowAngle(false);
		this.setHideCorner(true);
		this.setHideHand(true);
		
		Bitmap bitmap = null;
		try {
			bitmap = Bitmap.createBitmap(doc_width, doc_height,
					Bitmap.Config.ARGB_8888);

			bitmap.eraseColor(backgroundColor);
			draw(new Canvas(bitmap));

		} catch (OutOfMemoryError e) {
		} catch (Exception e) {
		}
		finally
		{
			this.option = restoreOption;
			this.option.isHideArc = this.option.isHideArc;
			this.setShowAngle(this.option.isShowAngle);
			this.setHideCorner(this.option.isHideCorner);
			this.setHideHand(this.option.isHideHand);
			this.setAlign(this.option.align);
			return bitmap;
		}
	}

	public void Initialize() {
		offset = new Point(0, 0);

		calSize();

		cosSeekBar.setProgress(Float.parseFloat(UDataStorage.getStrData(
				this.getContext(), "cosSeekValue", "0f")));
		
		tanSeekBar.setEnable(false);
		tanSeekBar.setHideCursor(true);
		mSinSeekBar.setCursorDirection(SeekBar.CURSOR_DIRECTION_R2L);
		setCosActive(true);
		calProgress(cosSeekBar, cosSeekBar.getProgress(),true);
		
		this.setActiveRegion(ACTIVE_REGION_SEEKBAR);
	}

	public void newStageWithAngle(boolean isCos, float angle) {
		angle = angle < 0.0f ? 0.0f : angle > 90.0f ? 90.0f : angle;
		if (isCos) {
			cosSeekBar.setProgress((float) (Math.cos(angle * Math.PI / 180)));
			calProgress(cosSeekBar, cosSeekBar.getProgress(),true);
		} else {
			cosSeekBar.setProgress((float) (Math.cos((90f-angle )* Math.PI / 180)));
			calProgress(cosSeekBar, cosSeekBar.getProgress(),true);
		}

	}

	public void newStageWithRedian(boolean isCos, float redian) {
		redian = redian < 0f ? 0f : redian > 1f ? 1f : redian;

		if (isCos) {
			cosSeekBar.setProgress(redian);
			calProgress(cosSeekBar, cosSeekBar.getProgress(),true);
		} else {
			sinSeekBar.setProgress(redian);
			calProgress(sinSeekBar, sinSeekBar.getProgress(),true);
		}
	}

	public float getSinAngle() {
		return 90f - cosDegree;
	}

	public float getCosAngle() {
		return cosDegree;
	}

	public float getSinRadian() {
		return this.sinSeekBar.getProgress();
	}

	public float getCosRadian() {
		return this.cosSeekBar.getProgress();
	}

	public void startFadeActive()
	{
		if(this.option.isCosActive)
		{
			this.mCosSeekBar.fadeActiveAnimation();
			this.cosSeekBar.fadeActiveAnimation();
		}
		else
		{
			this.mSinSeekBar.fadeActiveAnimation();
			this.sinSeekBar.fadeActiveAnimation();
		}
	}
	
	
	// ==========================================================
	// Listener Method
	// ==========================================================
	private InteractListener sinSeekBarListener;

	public void setSinListener(InteractListener listener) {
		this.sinSeekBarListener = listener;
		this.sinSeekBar.addListener(new SeekBarListener() {
			long lastTime = 0;
			
			@Override
			public void onSeekBarDragged(SeekBar obj, float progress) {
				sinSeekBarListener.onEndDrag(obj, progress,System.currentTimeMillis(),System.currentTimeMillis() - lastTime,obj.getCursorPoint());
			}

			@Override
			public void onSeekBarBeginDrag(SeekBar obj, float progress) {
				sinSeekBarListener.onBeginDrag(obj, progress,lastTime = System.currentTimeMillis(),obj.getCursorPoint());
			}

			@Override
			public void onSeekBarDragging(SeekBar obj, float progress) {
				sinSeekBarListener.onValueChange(obj, progress,System.currentTimeMillis(),obj.getCursorPoint());
			}
		});
	}

	private InteractListener cosSeekBarListener;

	public void setCosListener(InteractListener listener) {
		this.cosSeekBarListener = listener;
		this.cosSeekBar.addListener(new SeekBarListener() {
			long lastTime = 0;
			@Override
			public void onSeekBarDragged(SeekBar obj, float progress) {
				cosSeekBarListener.onEndDrag(obj, progress,System.currentTimeMillis(),System.currentTimeMillis() - lastTime,obj.getCursorPoint());
			}

			@Override
			public void onSeekBarBeginDrag(SeekBar obj, float progress) {
				cosSeekBarListener.onBeginDrag(obj, progress,lastTime = System.currentTimeMillis(),obj.getCursorPoint());
			}

			@Override
			public void onSeekBarDragging(SeekBar obj, float progress) {
				cosSeekBarListener.onValueChange(obj, progress,System.currentTimeMillis(),obj.getCursorPoint());
			}
		});
	}

	private InteractListener sinSlideListener;

	public void setSinSlideListener(InteractListener listener) {
		this.sinSlideListener = listener;
		this.mSinSeekBar.addListener(new SeekBarListener() {
			long lastTime = 0;
			@Override
			public void onSeekBarDragged(SeekBar obj, float progress) {
				sinSlideListener.onEndDrag(obj,(progress/option.thumb_length),System.currentTimeMillis(),System.currentTimeMillis() - lastTime,obj.getCursorPoint());
			}

			@Override
			public void onSeekBarBeginDrag(SeekBar obj, float progress) {
				sinSlideListener.onBeginDrag(obj,(progress/option.thumb_length),lastTime = System.currentTimeMillis(),obj.getCursorPoint());
			}

			@Override
			public void onSeekBarDragging(SeekBar obj, float progress) {
				sinSlideListener.onValueChange(obj,(progress/option.thumb_length),System.currentTimeMillis(),obj.getCursorPoint());
			}
		});
	}

	private InteractListener cosSlideListener;

	public void setCosSlideListener(InteractListener listener) {
		this.cosSlideListener = listener;
		this.mCosSeekBar.addListener(new SeekBarListener() {
			long lastTime = 0;
			@Override
			public void onSeekBarDragged(SeekBar obj, float progress) {
				cosSlideListener.onEndDrag(obj, progress/option.thumb_length,System.currentTimeMillis(),System.currentTimeMillis() - lastTime,obj.getCursorPoint());
			}

			@Override
			public void onSeekBarBeginDrag(SeekBar obj, float progress) {
				cosSlideListener.onBeginDrag(obj, progress/option.thumb_length,lastTime = System.currentTimeMillis(),obj.getCursorPoint());
			}

			@Override
			public void onSeekBarDragging(SeekBar obj, float progress) {
				cosSlideListener.onValueChange(obj, (progress/option.thumb_length),System.currentTimeMillis(),obj.getCursorPoint());
			}
		});
	}


	private InteractClickListener sinSpinListener;

	public void setSinSpinListener(InteractClickListener listener) {
		this.sinSpinListener = listener;
	}

	private InteractClickListener cosSpinListener;

	public void setCosSpinListener(InteractClickListener listener) {
		this.cosSpinListener = listener;
	}


	private InteractClickListener sinPlusListener;

	public void setSinPlusListener(InteractClickListener listener) {
		this.sinPlusListener = listener;
	}

	private InteractClickListener cosPlusListener;

	public void setCosPlusListener(InteractClickListener listener) {
		this.cosPlusListener = listener;
	}


	private InteractClickListener sinMinusListener;

	public void setSinMinusListener(InteractClickListener listener) {
		this.sinMinusListener = listener;
	}

	private InteractClickListener cosMinusListener;

	public void setCosMinusListener(InteractClickListener listener) {
		this.cosMinusListener = listener;
	}

	// ==========================================================
	// Event Method
	// ==========================================================

	public void onResume()
	{
		if (corner_cos_anim != null)corner_cos_anim.start();
		if (corner_sin_anim != null)corner_sin_anim.start();
	}

	public void onDestroy()
	{
		if (corner_cos_anim != null)corner_cos_anim.stop();
		if (corner_sin_anim != null)corner_sin_anim.stop();
	}

	@Override
	public void onClick(SpinButton obj) {
		if(obj==cosPlusBodaries)
		{
			float value = cosSeekBar.getProgress() + this.weight_point;
			cosSeekBar.setProgress(value>1?1:value);
			calProgress(cosSeekBar,value ,true);

			if(cosPlusListener!=null)
			cosPlusListener.onClick(obj, cosSeekBar.getProgress(), System.currentTimeMillis(), new Point());
			
			Log.w("Trigle", "SpinClickListener=>Click Plus cosSeekBar"+value);
		}
		if(obj==sinPlusBodaries)
		{
			float value = sinSeekBar.getProgress() + this.weight_point;
			sinSeekBar.setProgress(value>1?1:value);
			calProgress(sinSeekBar, value,true);
			Log.w("Trigle", "SpinClickListener=>Click Plus sinSeekBar"+value);
			if(sinPlusListener!=null)
			sinPlusListener.onClick(obj, sinSeekBar.getProgress(), System.currentTimeMillis(), new Point());
		}
		
		if(obj==cosMinusBodaries)
		{
			float value = cosSeekBar.getProgress() - this.weight_point;
			cosSeekBar.setProgress(value<0?0:value);
			calProgress(cosSeekBar, value,true);
			Log.w("Trigle", "SpinClickListener=>Click Minus cosSeekBar"+value);
			if(cosMinusListener!=null)
			cosMinusListener.onClick(obj, cosSeekBar.getProgress(), System.currentTimeMillis(), new Point());
		}
		if(obj==sinMinusBodaries)
		{
			float value = sinSeekBar.getProgress() - this.weight_point;
			sinSeekBar.setProgress(value<0?0:value);
			calProgress(sinSeekBar, value,true);
			Log.w("Trigle", "SpinClickListener=>Click Minus sinSeekBar"+value);
			if(sinMinusListener!=null)
			sinMinusListener.onClick(obj, sinSeekBar.getProgress(), System.currentTimeMillis(), new Point());
		}
		
		if(obj==cosLabelBodaries)
			if(cosSpinListener!=null)
				cosSpinListener.onClick(obj,cosSeekBar.getProgress(), System.currentTimeMillis(), new Point(cosMinusBodaries.bondary.left,cosMinusBodaries.bondary.top));
		if(obj==sinLabelBodaries)
			if(sinSpinListener!=null)
				sinSpinListener.onClick(obj, sinSeekBar.getProgress(), System.currentTimeMillis(), new Point(sinMinusBodaries.bondary.left,sinMinusBodaries.bondary.top));
		
	}
	
	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
	}
	

	@Override
	public void onSeekBarDragged(SeekBar obj, float progress) {
		calProgress(obj, progress,true);
		if(!this.option.isViewForAnimate)
		{
			if(!this.option.isHideLabel && obj==mCosSeekBar)
				cosSeekBar.setCoverLabel(false);
			if(!this.option.isHideLabel && obj==mSinSeekBar)
				sinSeekBar.setCoverLabel(false);
		}
	}

	@Override
	public void onSeekBarDragging(SeekBar obj, float progress) {
		calProgress(obj, progress,false);
	}

	@Override
	public void onSeekBarBeginDrag(SeekBar obj, float progress) {
		if(!this.option.isViewForAnimate)
		{
			if(!this.option.isHideLabel && obj==mCosSeekBar)
				cosSeekBar.setCoverLabel(true);
			if(!this.option.isHideLabel && obj==mSinSeekBar)
				sinSeekBar.setCoverLabel(true);
		}
	}

	@SuppressLint("NewApi")
	@Override
	protected void onDraw(Canvas canvas) {
		
		boolean isDraw = !this.option.isViewForAnimate
				&& this.option.isShowSeekBar
				&& (this.option.mode == MODE_DISPLAY || this.option.mode == MODE_CAPTURE_FULL);

		drawAngle(canvas);
		drawArc(canvas);
		drawBar(canvas,isDraw);
		drawCursorAndUnit(canvas,isDraw);
		drawCorner(canvas);
		
		drawSpin(canvas);
		drawLabel(canvas);
		drawHand(canvas);
	}
	
	//======================================================================
	// DRAW HELPER
	//======================================================================
	private void drawHand(Canvas canvas)
	{
		switch(this.option.pos_hand)
		{
			case POS_HAND_SLIDE:
				if(this.option.isMultiActive)
				{
					mSinSeekBar.drawHand(canvas);
					mCosSeekBar.drawHand(canvas);
				}
				else
				{
					if(!this.option.isCosActive)
						mSinSeekBar.drawHand(canvas);
					else
						mCosSeekBar.drawHand(canvas);
				}
				break;
			case POS_HAND_SEEKBAR:
				if(this.option.isMultiActive)
				{
					sinSeekBar.drawHand(canvas);
					cosSeekBar.drawHand(canvas);
				}
				else
				{
					if(!this.option.isCosActive)
						sinSeekBar.drawHand(canvas);
					else
						cosSeekBar.drawHand(canvas);
				}
				break;
			case POS_HAND_BOTH:
				if(this.option.isMultiActive)
				{
					sinSeekBar.drawHand(canvas);
					mSinSeekBar.drawHand(canvas);
					cosSeekBar.drawHand(canvas);
					mCosSeekBar.drawHand(canvas);
				}
				else
				{
					if(!this.option.isCosActive)
					{
						sinSeekBar.drawHand(canvas);
						mSinSeekBar.drawHand(canvas);
					}
					else
					{
						cosSeekBar.drawHand(canvas);
						mCosSeekBar.drawHand(canvas);
					}
				}
				break;
		}
	}
	
	private void drawAngle(Canvas canvas)
	{
		if (!this.option.isViewForAnimate && this.option.isShowAngle) {
			canvas.drawText(getContext().getString(R.string.display_cos), offset.x + this.object_width
					- 100 - 22, offset.y + this.object_width - 20, anglePaint);
			canvas.drawText(String.format("% ."+this.option.num_float_bit+"f", cosDegree), offset.x + 32 + this.object_width
					- 100, offset.y + this.object_width - 20, anglePaint);
			canvas.drawText(getContext().getString(R.string.display_sin), offset.x + 10, offset.y + 20,
					anglePaint);
			canvas.drawText(String.format("% ."+this.option.num_float_bit+"f", (90f-cosDegree)), offset.x + 15 + 42, offset.y + 20,
					anglePaint);
		}

	}
	
	private void drawArc(Canvas canvas)
	{
		if(!this.option.isHideArc)
			if(!this.option.multiCorner)
			{
		        if(this.option.isCosActive)
		        	canvas.drawArc (cosRectF, 180f,   cosDegree , true, markAnglePaint);
		        else
		        	canvas.drawArc (sinRectF,cosDegree, 90f - cosDegree, true, markAnglePaint);
		    }
			else
			{
				canvas.drawArc (cosRectF, 180f,   cosDegree , true, markAnglePaint);
	        	canvas.drawArc (sinRectF,cosDegree, 90f - cosDegree, true, markAnglePaint);
			}
		
	}

	private void drawBar(Canvas canvas,boolean isDraw)
	{
		if (isDraw) 
		{
			cosSeekBar.drawLine(canvas);
			sinSeekBar.drawLine(canvas);
			tanSeekBar.drawLine(canvas);
		}

		mSinSeekBar.drawLine(canvas);
		mCosSeekBar.drawLine(canvas);

		canvas.drawLine(mCosSeekBar.getCursorX(), mCosSeekBar.getCursorY(),
				mSinSeekBar.getCursorX(), mSinSeekBar.getCursorY(), tanPaint);
		
	}

	private void drawCursorAndUnit(Canvas canvas,boolean isDraw)
	{

		if (isDraw) {
			cosSeekBar.drawCursor(canvas);
			sinSeekBar.drawCursor(canvas);
			tanSeekBar.drawCursor(canvas);

			cosSeekBar.drawUnit(canvas);
			sinSeekBar.drawUnit(canvas);
			tanSeekBar.drawUnit(canvas);
		}

		mSinSeekBar.drawCursor(canvas);
		mCosSeekBar.drawCursor(canvas);

	}

	private void drawLabel(Canvas canvas)
	{
		cosSeekBar.drawLabel(canvas);
		sinSeekBar.drawLabel(canvas);
		tanSeekBar.drawLabel(canvas);
	}

	private void drawCorner(Canvas canvas)
	{
		if(!this.option.isHideCorner)
		{
			if(this.option.multiCorner)
			{
				corner_cos_anim.Draw(canvas);
				corner_sin_anim.Draw(canvas);
			}
			else
			{
				if(this.option.isCosActive)
					corner_cos_anim.Draw(canvas);
				else
					corner_sin_anim.Draw(canvas);
			}
		}
	}

	private void drawSpin(Canvas canvas)
	{
		if(this.option.mode==this.MODE_DISPLAY&&!this.option.isViewForAnimate)
		{
			if(active_region == ACTIVE_REGION_SPIN)
			{
				if(!cosMinusBodaries.pressed)
				{
					minusDrawable.setBounds(cosMinusBodaries.bondary);
					minusDrawable.draw(canvas);
				}
				else
				{
					Rect tmpREct = new Rect(
							cosMinusBodaries.bondary.left - (int)(cosMinusBodaries.bondary.width()*0.2),
							cosMinusBodaries.bondary.top - (int)(cosMinusBodaries.bondary.height()*0.2),
							cosMinusBodaries.bondary.right + (int)(cosMinusBodaries.bondary.width()*0.2),
							cosMinusBodaries.bondary.bottom + (int)(cosMinusBodaries.bondary.height()*0.2));
					minusHoverDrawable.setBounds(tmpREct);
					minusHoverDrawable.draw(canvas);
				}
			}
			else
			{
				minusInactiveDrawable.setBounds(cosMinusBodaries.bondary);
				minusInactiveDrawable.draw(canvas);
			}

			if(active_region == ACTIVE_REGION_SPIN)
			{
				labelDrawable.setBounds(cosLabelBodaries.bondary);
				labelDrawable.draw(canvas);
			}
			else
			{
				inactiveLabelDrawable.setBounds(cosLabelBodaries.bondary);
				inactiveLabelDrawable.draw(canvas);
			}
			
			String label = String.format("%.3f",cosSeekBar.getProgress());
			if(active_region == ACTIVE_REGION_SPIN)
			{
				canvas.drawText(this.getResources().getString(R.string.display_cos),vtCosSpinTxt.x,vtCosSpinTxt.y, titlePaint);
				canvas.drawText(label,cosLabelBodaries.bondary.left + (cosLabelBodaries.bondary.width() - spinPaint.measureText(label))/2,cosLabelBodaries.bondary.top + cosLabelBodaries.bondary.height()/2 , spinPaint);
			}
			else
			{
				canvas.drawText(this.getResources().getString(R.string.display_cos),vtCosSpinTxt.x,vtCosSpinTxt.y, titleInactivePaint);
				canvas.drawText(label,cosLabelBodaries.bondary.left + (cosLabelBodaries.bondary.width() - spinPaint.measureText(label))/2,cosLabelBodaries.bondary.top + cosLabelBodaries.bondary.height()/2 , spinInactivePaint);
			}

			if(active_region == ACTIVE_REGION_SPIN)
			{
				if(!cosPlusBodaries.pressed)
				{
					plusDrawable.setBounds(cosPlusBodaries.bondary);
					plusDrawable.draw(canvas);
				}
				else
				{
					Rect tmpREct = new Rect(
							cosPlusBodaries.bondary.left - (int)(cosPlusBodaries.bondary.width()*0.2),
							cosPlusBodaries.bondary.top - (int)(cosPlusBodaries.bondary.height()*0.2),
							cosPlusBodaries.bondary.right + (int)(cosPlusBodaries.bondary.width()*0.2),
							cosPlusBodaries.bondary.bottom + (int)(cosPlusBodaries.bondary.height()*0.2));
					plusHoverDrawable.setBounds(tmpREct);
					plusHoverDrawable.draw(canvas);
				}
			}
			else
			{
				plusInactiveDrawable.setBounds(cosPlusBodaries.bondary);;
				plusInactiveDrawable.draw(canvas);
			}
			
			if(active_region == ACTIVE_REGION_SPIN)
			{
				if(!sinMinusBodaries.pressed)
				{
					minusDrawable.setBounds(sinMinusBodaries.bondary);
					minusDrawable.draw(canvas);
				}
				else
				{
					Rect tmpREct = new Rect(
							sinMinusBodaries.bondary.left - (int)(sinMinusBodaries.bondary.width()*0.2),
							sinMinusBodaries.bondary.top - (int)(sinMinusBodaries.bondary.height()*0.2),
							sinMinusBodaries.bondary.right + (int)(sinMinusBodaries.bondary.width()*0.2),
							sinMinusBodaries.bondary.bottom + (int)(sinMinusBodaries.bondary.height()*0.2));
					minusHoverDrawable.setBounds(tmpREct);
					minusHoverDrawable.draw(canvas);
				}
			}
			else
			{
				minusInactiveDrawable.setBounds(sinMinusBodaries.bondary);
				minusInactiveDrawable.draw(canvas);
			}

			if(active_region == ACTIVE_REGION_SPIN)
			{
				labelDrawable.setBounds(sinLabelBodaries.bondary);
				labelDrawable.draw(canvas);
			}
			else
			{
				inactiveLabelDrawable.setBounds(sinLabelBodaries.bondary);
				inactiveLabelDrawable.draw(canvas);
			}
			
			label = String.format("%.3f",sinSeekBar.getProgress());
			if(active_region == ACTIVE_REGION_SPIN)
			{
				canvas.drawText(this.getResources().getString(R.string.display_sin),vtSinSpinTxt.x,vtSinSpinTxt.y, titlePaint);
				canvas.drawText(label,sinLabelBodaries.bondary.left + (sinLabelBodaries.bondary.width() - spinPaint.measureText(label))/2,sinLabelBodaries.bondary.top + sinLabelBodaries.bondary.height()/2 , spinPaint);
			}
			else
			{
				canvas.drawText(this.getResources().getString(R.string.display_sin),vtSinSpinTxt.x,vtSinSpinTxt.y, titleInactivePaint);
				canvas.drawText(label,sinLabelBodaries.bondary.left + (sinLabelBodaries.bondary.width() - spinPaint.measureText(label))/2,sinLabelBodaries.bondary.top + sinLabelBodaries.bondary.height()/2 , spinInactivePaint);
			}
			
			if(active_region == ACTIVE_REGION_SPIN)
			{
				if(!sinPlusBodaries.pressed)
				{
					plusDrawable.setBounds(sinPlusBodaries.bondary);
					plusDrawable.draw(canvas);
				}
				else
				{
					Rect tmpREct = new Rect(
							sinPlusBodaries.bondary.left - (int)(sinPlusBodaries.bondary.width()*0.2),
							sinPlusBodaries.bondary.top - (int)(sinPlusBodaries.bondary.height()*0.2),
							sinPlusBodaries.bondary.right + (int)(sinPlusBodaries.bondary.width()*0.2),
							sinPlusBodaries.bondary.bottom + (int)(sinPlusBodaries.bondary.height()*0.2));
					plusHoverDrawable.setBounds(tmpREct);
					plusHoverDrawable.draw(canvas);
				}
			}
			else
			{
				plusInactiveDrawable.setBounds(sinPlusBodaries.bondary);
				plusInactiveDrawable.draw(canvas);
			}
		}
	}
	
	//**********************************************************************
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);

		if (this.option.mode == MODE_DISPLAY) {
			// grab the pointer id
			int action = event.getAction();
			int pid = action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			int x = (int) event.getX(pid);
			int y = (int) event.getY(pid);
			if(!this.option.isLock)
			{
				return (touchSeekBar(action, x, y) || touchSpin(action, x, y));
			}
			else
			{
				if(!this.option.isHideCorner)
					return ((corner_sin_anim!=null&&corner_sin_anim.onTouch(action, x, y))
							|| (corner_cos_anim!=null&&corner_cos_anim.onTouch(action, x, y)));
			}
		}
		return false;
	}

	//======================================================================
	// SPIN HELPER
	//======================================================================
	public class SpinButton
	{
		public Rect bondary = null;
		public boolean pressed = false;
		public SpinClickListener listener = null;
		
		public SpinButton(){}
		
		public boolean onTouch(int action,int x ,int y)
		{
			if (action == MotionEvent.ACTION_DOWN) {
				if (bondary.contains(x, y)) {
					if(!pressed)
					{
						pressed = true;
						if(listener!=null)
							listener.onClick(this);
					}
					invalidate();
					return true;
				}
			} else if (action == MotionEvent.ACTION_UP
					|| action == MotionEvent.ACTION_CANCEL) {
				if (pressed) {
					pressed = false;
					invalidate();
					return false;
				}
			}
			return false;
		}
	}

	public static int ACTIVE_REGION_SEEKBAR = 1;
	public static int ACTIVE_REGION_SPIN = 2;
	private int active_region = ACTIVE_REGION_SEEKBAR;
	public void setActiveRegion(int active_region)
	{
		this.active_region = (active_region==ACTIVE_REGION_SEEKBAR||active_region==ACTIVE_REGION_SPIN)?active_region:ACTIVE_REGION_SEEKBAR;
		this.invalidate();
	}
	
	private boolean touchSeekBar(int action,int x ,int y)
	{
		if(active_region==ACTIVE_REGION_SEEKBAR)
		{
			return cosSeekBar.onTouch(action, x, y)
					|| sinSeekBar.onTouch(action, x, y)
					//|| tanSeekBar.onTouch(action, x, y)
					|| mSinSeekBar.onTouch(action, x, y) 
					|| mCosSeekBar.onTouch(action, x, y);
		}
		return false;
	}
	
	private boolean touchSpin(int action,int x ,int y)
	{
		if(active_region==ACTIVE_REGION_SPIN)
		{
			if(this.option.mode==this.MODE_DISPLAY&&!this.option.isViewForAnimate)
			{
				return (   cosMinusBodaries.onTouch(action, x, y)
						|| cosLabelBodaries.onTouch(action, x, y)
						|| cosPlusBodaries.onTouch(action, x, y) 
						|| sinMinusBodaries.onTouch(action, x, y)
						|| sinLabelBodaries.onTouch(action, x, y)
						|| sinPlusBodaries.onTouch(action, x, y));
			}
		}
		return false;
	}
	
	//**********************************************************************
	
	@Override
	protected void onSizeChanged(int width, int height, int oldw, int oldh) {
		super.onSizeChanged(width, height, oldw, oldh);

		if (this.option.mode == MODE_DISPLAY && width != doc_width
				|| height != doc_height) {
			doc_width = width;
			doc_height = height;
			calSize();
		}
	}
	
	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		if (this.option.mode == MODE_DISPLAY && this.getMeasuredWidth() != doc_width
				|| this.getMeasuredHeight() != doc_height) {
			doc_width = this.getMeasuredWidth();
			doc_height = this.getMeasuredHeight();
			calSize();
		}
	}
	
	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (this.option.mode == MODE_DISPLAY && this.getMeasuredWidth() != doc_width
				|| this.getMeasuredHeight() != doc_height) {
			doc_width = this.getMeasuredWidth();
			doc_height = this.getMeasuredHeight();
			calSize();
		}

	}

	
}